﻿using System;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Runtime.InteropServices;

namespace MCUPic.Core
{
    public class BinGen
    {
        string CachePath;
        Stream CacheStream;
        BinaryReader CacheReader;
        BinaryWriter CacheWriter;

        string _OutputFileName;

        /// <summary>
        /// 
        /// </summary>
        /// <param name="OutputPath"></param>
        /// <exception cref="IOException"></exception>
        public BinGen(string OutputPath)
        {
            do
            {
                string CacheName = RandomString(16);
                CachePath = OutputPath + "\\" + CacheName.ToString();
                if (!File.Exists(CachePath))
                {
                    break;
                }
            } while (true);
            CacheStream = new FileStream(CachePath, FileMode.CreateNew);
            CacheWriter = new BinaryWriter(CacheStream);
            CacheReader = new BinaryReader(CacheStream);

            _OutputFileName = OutputPath + "\\" + DateTime.Now.ToString("G").Replace("/", "_").Replace(":", "-");
        }

        private string RandomString(int length)
        {
            char[] chars = new char[length];
            int cnt = 0;
            char cTmp;
            Random random = new Random();
            while (cnt < length)
            {
                cTmp = (char)random.Next('0', 'z' + 1);
                if (Char.IsLetterOrDigit(cTmp))
                {
                    chars[cnt] = cTmp;
                    cnt++;
                }
            }
            return new string(chars);
        }

        bool Exists(string Name, string ex)
        {
            return File.Exists(Name + "\\" + ex);
        }
        internal void GenBinFromCache()
        {
            CacheWriter.Flush();
            Stream BinStream = new FileStream(_OutputFileName + ".bin", FileMode.CreateNew);
            CacheStream.Seek(0, SeekOrigin.Begin);
            CacheStream.CopyTo(BinStream);
            BinStream.Close();
        }

        internal void GenCCodeFromCache(IScreenWindow size)
        {
            CacheWriter.Flush();
            Stream CCodeStream = new FileStream(_OutputFileName + ".c", FileMode.CreateNew);
            StreamWriter sw = new StreamWriter(CCodeStream);
            CacheStream.Seek(0, SeekOrigin.Begin);

            string Head = $"const unsigned short bmp1[{size.ScreenWidth}*{size.ScreenHeight}] = {{";
            sw.WriteLine(Head);
            try
            {
                byte[] buffer = new byte[18];
                string line = "";
                for (int row = 0; true; row++)
                {
                    if (row > 100)
                        sw.Flush();
                    
                    int ReadCnt = CacheReader.Read(buffer, 0, 18) / 2;
                    DataBox dataBox = new DataBox(buffer);
                    if (ReadCnt > 0)
                    {
                        if (row != 0) sw.WriteLine(",");
                        line = "    0x" + dataBox.UInt16[0].ToString("X4");
                        for (int i = 1; i < ReadCnt; i++)
                        {
                            line += ", 0x" + dataBox.UInt16[i].ToString("X4");
                        }
                        sw.Write(line);
                    }
                    else
                    {
                        sw.WriteLine();
                        sw.WriteLine("};");
                        break;
                    }
                }
            }
            catch (Exception)
            {
                throw;
            }


            sw.Close();
        }
        internal void AddCache(Bitmap pic, bool msbf)
        {
            Rectangle rect = new Rectangle(0, 0, pic.Width, pic.Height);
            BitmapData data = pic.LockBits(rect, ImageLockMode.ReadWrite, pic.PixelFormat);
            int OnePixbyteCnt = 2; 
            if (pic.PixelFormat == PixelFormat.Format16bppRgb565)
            {
                OnePixbyteCnt = 2;
            }

            for (int pixelcnt = 0; pixelcnt < pic.Width * pic.Height; pixelcnt++)
            {
                int startByte = 0;
                int dir = 1;
                if (msbf)
                {
                    startByte = OnePixbyteCnt - 1;
                    dir = -1;
                }
                for (int i = 0; i < OnePixbyteCnt; i++)
                {
                    CacheWriter.Write(Marshal.ReadByte(data.Scan0, pixelcnt * OnePixbyteCnt + startByte + i * dir));
                }
            }

            pic.UnlockBits(data);
            pic.Dispose();
        }


        //uint argb = ((uint)color.ToArgb());
        //byte[] argbArray = BitConverter.GetBytes(argb);

        //uint dstargb = (uint)((((argbArray[2] >> 3) & 0x1F) << 11) | (((argbArray[1] >> 2) & 0x3F) << 5) | ((argbArray[0] >> 3) & 0x1F));
        //byte[] byteToWrite;
        //byteToWrite = BitConverter.GetBytes(dstargb);

        //binaryWriter.Write(byteToWrite, 0, 2);


        internal void Release()
        {
            CacheWriter.Close();
            File.Delete(CachePath);

        }
    }
}
